package com.ruoyi.socket.manager;

import com.ruoyi.socket.config.BinanceWebSocketConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 币安连接管理器
 * 管理连接状态，实现智能重连和地址切换
 */
@Component
@Slf4j
public class BinanceConnectionManager {
    
    @Resource
    private BinanceWebSocketConfig binanceWebSocketConfig;
    
    /**
     * 连接失败计数器
     */
    private final AtomicInteger failureCount = new AtomicInteger(0);
    
    /**
     * 连接状态映射
     */
    private final ConcurrentHashMap<String, Boolean> connectionStatus = new ConcurrentHashMap<>();
    
    /**
     * 最后连接时间
     */
    private volatile long lastConnectTime = 0;
    
    /**
     * 获取当前WebSocket URL
     */
    public String getCurrentWebSocketUrl(String path) {
        return binanceWebSocketConfig.buildWebSocketUrl(path);
    }
    
    /**
     * 处理连接失败
     * @param reason 失败原因
     * @return 是否需要切换地址
     */
    public boolean handleConnectionFailure(String reason) {
        int currentFailures = failureCount.incrementAndGet();
        String currentUrl = binanceWebSocketConfig.getCurrentUrl();
        
        log.warn("币安WebSocket连接失败 [{}]: {}, 当前失败次数: {}", 
                currentUrl, reason, currentFailures);
        
        // 记录连接状态
        connectionStatus.put(currentUrl, false);
        
        // 如果是HTTP 451错误或连接失败次数达到阈值，切换地址
        if (reason.contains("451") || currentFailures >= binanceWebSocketConfig.getMaxRetries()) {
            return switchToNextUrl();
        }
        
        return false;
    }
    
    /**
     * 切换到下一个地址
     */
    public boolean switchToNextUrl() {
        String oldUrl = binanceWebSocketConfig.getCurrentUrl();
        String newUrl = binanceWebSocketConfig.switchToNextUrl();
        
        if (!oldUrl.equals(newUrl)) {
            log.info("币安WebSocket地址切换: {} -> {}", oldUrl, newUrl);
            failureCount.set(0); // 重置失败计数
            return true;
        }
        
        // 如果所有地址都尝试过了，重置到第一个地址
        if (binanceWebSocketConfig.getCurrentUrlIndex() == 0) {
            log.warn("所有币安WebSocket地址都已尝试，重置到第一个地址");
            binanceWebSocketConfig.resetToFirstUrl();
            failureCount.set(0);
        }
        
        return false;
    }
    
    /**
     * 处理连接成功
     */
    public void handleConnectionSuccess() {
        String currentUrl = binanceWebSocketConfig.getCurrentUrl();
        log.info("币安WebSocket连接成功: {}", currentUrl);
        
        // 重置失败计数
        failureCount.set(0);
        
        // 记录连接状态
        connectionStatus.put(currentUrl, true);
        lastConnectTime = System.currentTimeMillis();
    }
    
    /**
     * 是否应该重连
     */
    public boolean shouldReconnect() {
        long timeSinceLastConnect = System.currentTimeMillis() - lastConnectTime;
        return timeSinceLastConnect >= binanceWebSocketConfig.getReconnectInterval();
    }
    
    /**
     * 获取连接状态信息
     */
    public String getConnectionStatusInfo() {
        StringBuilder sb = new StringBuilder();
        sb.append("当前地址: ").append(binanceWebSocketConfig.getCurrentUrl()).append("\n");
        sb.append("地址索引: ").append(binanceWebSocketConfig.getCurrentUrlIndex() + 1)
          .append("/").append(binanceWebSocketConfig.getUrlCount()).append("\n");
        sb.append("失败次数: ").append(failureCount.get()).append("\n");
        sb.append("连接状态: ");
        
        connectionStatus.forEach((url, status) -> {
            sb.append("\n  ").append(url).append(": ").append(status ? "成功" : "失败");
        });
        
        return sb.toString();
    }
    
    /**
     * 重置连接状态
     */
    public void resetConnectionStatus() {
        failureCount.set(0);
        connectionStatus.clear();
        binanceWebSocketConfig.resetToFirstUrl();
        log.info("币安WebSocket连接状态已重置");
    }
    
    /**
     * 检查是否需要切换地址
     */
    public boolean needsUrlSwitch(String errorMessage) {
        // HTTP 451 (法律原因不可用) 立即切换
        if (errorMessage.contains("451")) {
            log.warn("检测到HTTP 451错误，立即切换币安WebSocket地址");
            return true;
        }
        
        // 连接超时或拒绝连接
        if (errorMessage.contains("timeout") || errorMessage.contains("refused") || 
            errorMessage.contains("unreachable")) {
            return failureCount.get() >= 2; // 2次失败后切换
        }
        
        // 其他错误，3次失败后切换
        return failureCount.get() >= binanceWebSocketConfig.getMaxRetries();
    }
} 